/* Classic Ladder Project */
/* Copyright (C) 2001-2012 Marc Le Douarain */
/* http://membres.lycos.fr/mavati/classicladder/ */
/* http://www.sourceforge.net/projects/classicladder */
/* February 2001 */
/* -------------------------------------------------------------------------------------------- */
/* Spy variables windows (booleans with checkboxes, and any with entry widgets) - GTK interface */
/* + Modify current value of a spy variable                                                     */
/* -------------------------------------------------------------------------------------------- */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/* Lesser General Public License for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <gtk/gtk.h>

#include "classicladder.h"
#include "global.h"
#include "vars_access.h"
#include "drawing.h"
#include "edit.h"
#include "classicladder_gtk.h"
#include "vars_names.h"
#include "symbols.h"
#include "menu_and_toolbar_gtk.h"
#include "preferences.h"

#include "spy_vars_gtk.h"

//#define NBR_BOOLS_VAR_SPY 15
//#define NBR_TYPE_BOOLS_SPY 3
//#define NBR_FREE_VAR_SPY 10

GtkWidget *SpyBoolVarsWindow;
GtkWidget *SpyFreeVarsWindow;
GtkWidget *ModifyVarValueWindow;

GtkWidget *offsetboolvar[ NBR_TYPE_BOOLS_SPY ];
//new InfosGUI! int ValOffsetBoolVar[ NBR_TYPE_BOOLS_SPY ] = { 0, 0, 0 };
GtkWidget *chkvar[ NBR_TYPE_BOOLS_SPY ][ NBR_BOOLS_VAR_SPY ];
GtkTooltips * TooltipsBoolVar[ NBR_TYPE_BOOLS_SPY ][ NBR_BOOLS_VAR_SPY ];
GtkWidget *DisplaySymbolsForBoolVars;

GtkWidget * EntryDateTime;
enum {VAR_SPY_MODE_DEC_SIGNED, VAR_SPY_MODE_DEC_UNSIGNED, VAR_SPY_MODE_HEX, VAR_SPY_MODE_BIN, VAR_SPY_MODE_END};
GtkWidget * EntryVarSpy[NBR_FREE_VAR_SPY*2];
GtkTooltips * TooltipsEntryVarSpy[ NBR_FREE_VAR_SPY ];
/* defaults vars to spy list */
//new InfosGUI! int VarSpy[NBR_FREE_VAR_SPY][2] = { {VAR_MEM_WORD,0}, {VAR_MEM_WORD,1}, {VAR_MEM_WORD,2}, {VAR_MEM_WORD,3}, {VAR_MEM_WORD,4}, {VAR_MEM_WORD,5}, {VAR_MEM_WORD,6}, {VAR_MEM_WORD,7}, {VAR_MEM_WORD,8}, {VAR_MEM_WORD,9} };
GtkWidget * DisplayFormatVarSpy[NBR_FREE_VAR_SPY];
//GtkWidget * ModifyVarSpy[NBR_FREE_VAR_SPY];
GtkWidget * EditVarSpyValue[NBR_FREE_VAR_SPY];
int LatestEditedVarValue[ NBR_FREE_VAR_SPY ];

GtkWidget * ModifyVariableNameEdit;
GtkWidget * ModifyVariableValueEdit;
int CurrentModifyVarType, CurrentModifyVarOffset;
int SaveModifyVarPosX = -1;
int SaveModifyVarPosY = -1;

#define NBR_TARGET_INFOS 3
GtkWidget * TargetInfoEntry[ NBR_TARGET_INFOS ];
#define NBR_PROJECT_INFOS 5
GtkWidget * ProjectInfoEntry[ NBR_PROJECT_INFOS ];

static gint chkvar_press_event( GtkWidget      *widget, void * numcheck )
{
	long NumCheckWidget = (long)numcheck;
	int Type = VAR_MEM_BIT;
	int Offset = InfosGUI->ValOffsetBoolVar[ 0 ];
	int NumCheck = NumCheckWidget;
	if( NumCheckWidget>=NBR_BOOLS_VAR_SPY && NumCheckWidget<2*NBR_BOOLS_VAR_SPY )
	{
		Type = VAR_PHYS_INPUT;
		Offset = InfosGUI->ValOffsetBoolVar[ 1 ];
		NumCheck -= NBR_BOOLS_VAR_SPY;
	} 
	if( NumCheckWidget>=2*NBR_BOOLS_VAR_SPY && NumCheckWidget<3*NBR_BOOLS_VAR_SPY )
	{
		Type = VAR_PHYS_OUTPUT;
		Offset = InfosGUI->ValOffsetBoolVar[ 2 ];
		NumCheck -= 2*NBR_BOOLS_VAR_SPY;
	} 
	if (gtk_toggle_button_get_active((GtkToggleButton *)widget))
	{
//Using InputStateForLogic at -1 now...		if ( Type==VAR_PHYS_INPUT )
//			InputFilterAndStateArray[ Offset+NumCheck ].InputStateForLogic = 1;
//		else
//TODO: test, if not -1, do not do anything?!
			WriteVar(Type,Offset+NumCheck,1);
//printf("check var=%d/%d to on\n",Type,Offset+NumCheck);
	}
	else
	{
//Using InputStateForLogic at -1 now...		if ( Type==VAR_PHYS_INPUT )
//			InputFilterAndStateArray[ Offset+NumCheck ].InputStateForLogic = 0;
//		else
//TODO: test, if not -1, do not do anything?!
			WriteVar(Type,Offset+NumCheck,0);
//printf("check var=%d/%d to off\n",Type,Offset+NumCheck);
	}
	return TRUE;
}

void RefreshOneBoolVar( int Type, int Num, int Val )
{
	int Col = 0;
	switch( Type )
	{
		case VAR_PHYS_INPUT: Col = 1; break;
		case VAR_PHYS_OUTPUT: Col = 2; break;
	}
	if ( Num>=InfosGUI->ValOffsetBoolVar[ Col ] && Num<InfosGUI->ValOffsetBoolVar[ Col ]+NBR_BOOLS_VAR_SPY )
		gtk_toggle_button_set_active((GtkToggleButton *)chkvar[Col][Num-InfosGUI->ValOffsetBoolVar[ Col ]],(Val!=0)?TRUE:FALSE);
}

void RefreshAllBoolsVars( )
{
	int NumVar;
	for (NumVar=0; NumVar<NBR_BOOLS_VAR_SPY; NumVar++)
	{
		gtk_toggle_button_set_active( (GtkToggleButton *)chkvar[0][NumVar], ReadVar(VAR_MEM_BIT,NumVar+InfosGUI->ValOffsetBoolVar[ 0 ])?TRUE:FALSE );
		gtk_toggle_button_set_active( (GtkToggleButton *)chkvar[1][NumVar], ReadVar(VAR_PHYS_INPUT,NumVar+InfosGUI->ValOffsetBoolVar[ 1 ])?TRUE:FALSE );
		gtk_toggle_button_set_active( (GtkToggleButton *)chkvar[2][NumVar], ReadVar(VAR_PHYS_OUTPUT,NumVar+InfosGUI->ValOffsetBoolVar[ 2 ])?TRUE:FALSE );
	}
}

void UpdateAllLabelsBoolsVars( int OnlyThisColumn )
{
	int ColumnVar, OffVar;
	char DisplaySymbol = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( DisplaySymbolsForBoolVars ) );
	for(ColumnVar=0; ColumnVar<NBR_TYPE_BOOLS_SPY; ColumnVar++)
	{
		char Buffer[20];
		if ( OnlyThisColumn==-1 || OnlyThisColumn==ColumnVar )
		{
			for(OffVar=0; OffVar<NBR_BOOLS_VAR_SPY; OffVar++)
			{
				char * OtherVarName;
				switch( ColumnVar )
				{
					case 0: sprintf(Buffer, "%cB%d",'%', OffVar+InfosGUI->ValOffsetBoolVar[ ColumnVar ]); break;
					case 1: sprintf(Buffer, "%cI%d",'%', OffVar+InfosGUI->ValOffsetBoolVar[ ColumnVar ]); break;
					case 2: sprintf(Buffer, "%cQ%d",'%', OffVar+InfosGUI->ValOffsetBoolVar[ ColumnVar ]); break;
				}
				OtherVarName = ConvVarNameToSymbol( Buffer );
				if ( OtherVarName==NULL )
					OtherVarName = "";
				gtk_label_set_text(GTK_LABEL(GTK_BIN( chkvar[ ColumnVar ][ OffVar ] )->child), (DisplaySymbol && OtherVarName[0]!='\0')?OtherVarName:Buffer);
				gtk_tooltips_set_tip ( TooltipsBoolVar[ ColumnVar ][ OffVar ], chkvar[ ColumnVar ][ OffVar ], (DisplaySymbol && OtherVarName[0]!='\0')?Buffer:OtherVarName, NULL );
			}
		}
		if ( OnlyThisColumn==-1 )
		{
			sprintf( Buffer, "%d", InfosGUI->ValOffsetBoolVar[ ColumnVar ] );
			gtk_entry_set_text( GTK_ENTRY(offsetboolvar[ ColumnVar ]), Buffer );
		}
	}
}

static gint OffsetBoolVar_activate_event( GtkWidget *widget, void * NumVarSpy )
{
	int Maxi = 0;
	long NumType = (long)NumVarSpy;
	int ValOffset = atoi( gtk_entry_get_text((GtkEntry *)widget) );
	switch( NumType )
	{
		case 0: Maxi = NBR_BITS; break;
		case 1: Maxi = NBR_PHYS_INPUTS; break;
		case 2: Maxi = NBR_PHYS_OUTPUTS; break;
	}
	if ( ValOffset+NBR_BOOLS_VAR_SPY>Maxi || ValOffset<0 )
		ValOffset = 0;
	InfosGUI->ValOffsetBoolVar[ NumType ] = ValOffset;
	UpdateAllLabelsBoolsVars( NumType/*OnlyThisColumn*/ );
	RefreshAllBoolsVars( );
	return TRUE;
}

static gint ChangeDisplaySymbolsForBoolVars_event( GtkWidget *widget, void * NotUsed )
{	
	UpdateAllLabelsBoolsVars( -1/*ALL Columns*/ );
	return TRUE;
}

gint BoolVarsWindowDeleteEvent( GtkWidget * widget, GdkEvent * event, gpointer data )
{
// Here, we must only toggle the menu check that will call itself the function below to close the window ...
//	gtk_widget_hide( SpyBoolVarsWindow );
	SetToggleMenuForBoolVarsWindow( FALSE/*OpenedWin*/ );
	// we do not want that the window be destroyed.
	return TRUE;
}

// called per toggle action menu, or at startup (if window saved open or not)...
void OpenSpyBoolVarsWindow( GtkAction * ActionOpen, gboolean OpenIt )
{
	if ( ActionOpen!=NULL )
		OpenIt = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(ActionOpen) );
	if ( OpenIt )
	{
		RestoreWindowPosiPrefs( "BoolVars", SpyBoolVarsWindow );
		gtk_widget_show( SpyBoolVarsWindow );
		gtk_window_present( GTK_WINDOW(SpyBoolVarsWindow) );
	}
	else
	{
		RememberWindowPosiPrefs( "BoolVars", SpyBoolVarsWindow, FALSE/*SaveWindowSize*/ );
		gtk_widget_hide( SpyBoolVarsWindow );
	}
}
void RememberBoolVarsWindowPrefs( void )
{
	char WindowIsOpened = GTK_WIDGET_VISIBLE( GTK_WINDOW(SpyBoolVarsWindow) );
	RememberWindowOpenPrefs( "BoolVars", WindowIsOpened );
	if ( WindowIsOpened )
		RememberWindowPosiPrefs( "BoolVars", SpyBoolVarsWindow, FALSE/*SaveWindowSize*/ );
}

void BoolVarsWindowInitGtk()
{
	GtkWidget *vboxboolvars[ NBR_TYPE_BOOLS_SPY ],*vboxmain,*hboxvars;
	GtkWidget *Hbox1;
	long NumCheckWidget,ColumnVar;
	GtkTooltips * WidgetTooltips[ NBR_TYPE_BOOLS_SPY ];
	
	SpyBoolVarsWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title ((GtkWindow *)SpyBoolVarsWindow, "Spy bools vars");
	vboxmain = gtk_vbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (SpyBoolVarsWindow), vboxmain);
//	gtk_widget_show (vboxmain);

	Hbox1 = gtk_hbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (vboxmain), Hbox1);
//	gtk_widget_show (Hbox1);
	DisplaySymbolsForBoolVars = gtk_check_button_new_with_label("Display Symbols");
	gtk_box_pack_start (GTK_BOX(Hbox1), DisplaySymbolsForBoolVars, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT (DisplaySymbolsForBoolVars), "toggled",
					(GtkSignalFunc) ChangeDisplaySymbolsForBoolVars_event, NULL );
//	gtk_widget_show (DisplaySymbolsForBoolVars);

	hboxvars = gtk_hbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (vboxmain), hboxvars);
//	gtk_widget_show (hboxvars);

	for( ColumnVar=0; ColumnVar<NBR_TYPE_BOOLS_SPY; ColumnVar++ )
	{
		vboxboolvars[ ColumnVar ] = gtk_vbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (hboxvars), vboxboolvars[ ColumnVar ]);
//		gtk_widget_show (vboxboolvars[ ColumnVar ]);
	}

	NumCheckWidget = 0;
	for(ColumnVar=0; ColumnVar<NBR_TYPE_BOOLS_SPY; ColumnVar++)
	{
		int OffVar;
		offsetboolvar[ ColumnVar ]  = gtk_entry_new();
		WidgetTooltips[ ColumnVar ] = gtk_tooltips_new();
		gtk_tooltips_set_tip ( WidgetTooltips[ ColumnVar ], offsetboolvar[ ColumnVar ], "Offset for vars displayed below (press return to apply)", NULL );
		gtk_widget_set_usize((GtkWidget *)offsetboolvar[ ColumnVar ],40,0);
		gtk_box_pack_start (GTK_BOX(vboxboolvars[ ColumnVar ]),  offsetboolvar[ ColumnVar ] , FALSE, FALSE, 0);
//		gtk_widget_show( offsetboolvar[ ColumnVar ] );
		gtk_entry_set_text((GtkEntry *)offsetboolvar[ ColumnVar ],"0");
		gtk_signal_connect(GTK_OBJECT (offsetboolvar[ ColumnVar ]), "activate",
					(GtkSignalFunc) OffsetBoolVar_activate_event, (void *)ColumnVar);
		
		for(OffVar=0; OffVar<NBR_BOOLS_VAR_SPY; OffVar++)
		{
			chkvar[ ColumnVar ][ OffVar ] = gtk_check_button_new_with_label("xxxx");
			gtk_box_pack_start (GTK_BOX(vboxboolvars[ ColumnVar ]), chkvar[ ColumnVar ][ OffVar ], FALSE, FALSE, 0);
//			gtk_widget_show(chkvar[ ColumnVar ][ OffVar ]);
			gtk_signal_connect(GTK_OBJECT (chkvar[ ColumnVar ][ OffVar ]), "toggled",
					(GtkSignalFunc) chkvar_press_event, (void*)NumCheckWidget);
			TooltipsBoolVar[ ColumnVar ][ OffVar ] = gtk_tooltips_new();
			NumCheckWidget++;
		}
	}
	UpdateAllLabelsBoolsVars( -1/*OnlyThisColumn*/ );
	
	gtk_widget_show_all(SpyBoolVarsWindow);

	gtk_signal_connect( GTK_OBJECT(SpyBoolVarsWindow), "delete_event",
		(GtkSignalFunc)BoolVarsWindowDeleteEvent, 0 );

//	gtk_window_set_policy( GTK_WINDOW(SpyBoolVarsWindow), FALSE/*allow_shrink*/, FALSE/*allow_grow*/, TRUE/*auto_shrink*/ );
}



//NO MORE USED, SINCE EDIT WIDGET AT THE RIGHT OF EACH SPY...
#ifdef AAAAAAAAAAAAAAAAAAAA
static gint OpenModifyVarWindow_clicked_event(GtkWidget *widget, int NumSpy)
{
	char BuffValue[ 30 ];
	CurrentModifyVarType = InfosGUI->FreeVarSpy[NumSpy].VarType;
	CurrentModifyVarOffset = InfosGUI->FreeVarSpy[NumSpy].VarNum;

	gtk_entry_set_text( GTK_ENTRY(ModifyVariableNameEdit), CreateVarName(CurrentModifyVarType,CurrentModifyVarOffset,InfosGene->DisplaySymbols) );
	sprintf( BuffValue, "%d", ReadVar(CurrentModifyVarType, CurrentModifyVarOffset) );
	gtk_entry_set_text( GTK_ENTRY(ModifyVariableValueEdit), BuffValue );
	gtk_widget_grab_focus( ModifyVariableValueEdit );

	gtk_widget_show( ModifyVarValueWindow );
	if ( SaveModifyVarPosX!=-1 && SaveModifyVarPosY!=-1 )
		gtk_window_move( GTK_WINDOW(ModifyVarValueWindow), SaveModifyVarPosX, SaveModifyVarPosY );

	return TRUE;
}
gint ModifyVarWindowDeleteEvent( GtkWidget * widget, GdkEvent * event, gpointer data )
{
	gtk_window_get_position( GTK_WINDOW(ModifyVarValueWindow), &SaveModifyVarPosX, &SaveModifyVarPosY );
	gtk_widget_hide( ModifyVarValueWindow );
	// we do not want that the window be destroyed.
	return TRUE;
}
gint ApplyModifiedVar( GtkWidget * widget, GdkEvent * event, gpointer data )
{
	int NewValue = atoi( gtk_entry_get_text( GTK_ENTRY(ModifyVariableValueEdit) ) );
	WriteVar( CurrentModifyVarType, CurrentModifyVarOffset, NewValue );
	gtk_window_get_position( GTK_WINDOW(ModifyVarValueWindow), &SaveModifyVarPosX, &SaveModifyVarPosY );
	gtk_widget_hide( ModifyVarValueWindow );
	// we do not want that the window be destroyed.
	return TRUE;
}
void ModifyVarWindowInitGtk( )
{
	GtkWidget *vboxMain,*hboxOkCancel;
	GtkWidget *ButtonOk,*ButtonCancel;
	ModifyVarValueWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title ((GtkWindow *)ModifyVarValueWindow, "Modify variable value");
	vboxMain = gtk_vbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (ModifyVarValueWindow), vboxMain);
	gtk_widget_show (vboxMain);

	ModifyVariableNameEdit = gtk_entry_new();
//	gtk_widget_set_usize( GTK_WIDGET(ModifyVariableValueEdit),110,0);
	gtk_box_pack_start (GTK_BOX( vboxMain ), ModifyVariableNameEdit, TRUE, TRUE, 0);
	gtk_editable_set_editable( GTK_EDITABLE(ModifyVariableNameEdit), FALSE );
	gtk_widget_show( ModifyVariableNameEdit );

	ModifyVariableValueEdit = gtk_entry_new();
//	gtk_widget_set_usize( GTK_WIDGET(ModifyVariableValueEdit),110,0);
	gtk_box_pack_start (GTK_BOX( vboxMain ), ModifyVariableValueEdit, TRUE, TRUE, 0);
	gtk_widget_show( ModifyVariableValueEdit );
	gtk_signal_connect( GTK_OBJECT(ModifyVariableValueEdit), "activate",
                                        (GtkSignalFunc) ApplyModifiedVar, (void *)NULL );

	hboxOkCancel = gtk_hbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (vboxMain), hboxOkCancel);
	gtk_widget_show (hboxOkCancel);

	ButtonOk = gtk_button_new_from_stock( GTK_STOCK_OK );
	gtk_box_pack_start( GTK_BOX(hboxOkCancel), ButtonOk, FALSE, FALSE, 0 );
	gtk_widget_show( ButtonOk );
	gtk_signal_connect( GTK_OBJECT(ButtonOk), "clicked",
                                        (GtkSignalFunc)ApplyModifiedVar, (void *)NULL );
	ButtonCancel = gtk_button_new_from_stock( GTK_STOCK_CANCEL );
	gtk_box_pack_start( GTK_BOX(hboxOkCancel), ButtonCancel, FALSE, FALSE, 0 );
	gtk_widget_show( ButtonCancel );
	gtk_signal_connect( GTK_OBJECT(ButtonCancel), "clicked",
                                        (GtkSignalFunc)ModifyVarWindowDeleteEvent, NULL );

	gtk_signal_connect( GTK_OBJECT(ModifyVarValueWindow), "delete_event",
		(GtkSignalFunc)ModifyVarWindowDeleteEvent, 0 );
}
#endif



static int ConvBinToInt (const char *Ascii)
{
	int Pos, Value, Len;

  Value=0;
  Len=strlen(Ascii);
  for (Pos=0; Pos<Len; Pos++)
  {
  	Value*=2;
    if (Ascii[Pos]!='0') Value+=1;
  }	
  return Value;
}

char * ConvIntToBin( unsigned int Val )
{
	static char TabBin[ 33 ];
	int Pos;
	unsigned int Mask = 0x80000000;
	char First1 = FALSE;
	strcpy( TabBin, "" );
	for ( Pos = 0; Pos<32; Pos++ )
	{
		if ( Val & Mask )
			First1 = TRUE;
		if ( First1 )
		{
			if ( Val & Mask )
				strcat( TabBin, "1" );
			else
				strcat( TabBin, "0" );
		}
		Mask = Mask>>1;
	}
	if ( Val==0 )
		strcpy( TabBin,"0" );
	return TabBin;
}

char * FormatVariableValue( char *BufferValue, int Format, int Value )
{	
	switch(Format)
	{
		case VAR_SPY_MODE_DEC_SIGNED: 
			sprintf(BufferValue,"%d",Value); break;
		case VAR_SPY_MODE_DEC_UNSIGNED: 
			sprintf(BufferValue,"%u",Value); break;	
		case VAR_SPY_MODE_HEX: 
			sprintf(BufferValue,"%X",Value); break;
		case VAR_SPY_MODE_BIN: 
			strcpy( BufferValue, ConvIntToBin( Value ) ); break;
	}
	return BufferValue;
}

static gint EntryVarSpy_activate_event(GtkWidget *widget, int NumSpy)
{
	int NewVarType,NewVarOffset;
//	int * NumVarSpy = &InfosGUI->VarSpy[NumSpy].VarType;
	char BufferVar[30];
	strcpy(BufferVar, gtk_entry_get_text((GtkEntry *)widget) );
	if (TextParserForAVar(BufferVar , &NewVarType, &NewVarOffset, NULL, FALSE/*PartialNames*/))
	{
//		*NumVarSpy++ = NewVarType;
//		*NumVarSpy = NewVarOffset;
		InfosGUI->FreeVarSpy[NumSpy].VarType = NewVarType;
		InfosGUI->FreeVarSpy[NumSpy].VarNum = NewVarOffset;
		UpdateAllLabelsFreeVars( NumSpy, BufferVar );
	}
	else
	{
		int OldType,OldOffset;
		/* Error Message */
		if (ErrorMessageVarParser)
			ShowMessageBox("Error",ErrorMessageVarParser,"Ok");
		else
			ShowMessageBox( "Error", "Unknown variable...", "Ok" );
//		OldType = *NumVarSpy++;
//		OldOffset = *NumVarSpy;
		OldType = InfosGUI->FreeVarSpy[NumSpy].VarType;
		OldOffset = InfosGUI->FreeVarSpy[NumSpy].VarNum;
		/* put back old correct var */
		gtk_entry_set_text((GtkEntry *)widget,CreateVarName(OldType,OldOffset,InfosGene->DisplaySymbols));
	}
	return TRUE;
}

static gint ComboBox_changed_event(GtkWidget *widget, int NumVarSpy)
{
	char BufferValue[50];

	InfosGUI->FreeVarSpyDisplayFormat[NumVarSpy] = gtk_combo_box_get_active( GTK_COMBO_BOX( DisplayFormatVarSpy[NumVarSpy] ) );
	// display latest value entered with new display format selected
	gtk_entry_set_text((GtkEntry *)EditVarSpyValue[NumVarSpy], FormatVariableValue(BufferValue, InfosGUI->FreeVarSpyDisplayFormat[NumVarSpy],
						LatestEditedVarValue[NumVarSpy] ));
	return TRUE;
}	

static gint EditVarSpyValue_changed_event(GtkWidget *widget, int NumVarSpy)
{
	int NewValue;
	char BufferValue[50];

	CurrentModifyVarType = InfosGUI->FreeVarSpy[NumVarSpy].VarType;
	CurrentModifyVarOffset = InfosGUI->FreeVarSpy[NumVarSpy].VarNum;

	switch(InfosGUI->FreeVarSpyDisplayFormat[NumVarSpy])
	{
		case VAR_SPY_MODE_DEC_SIGNED: 
				sscanf (gtk_entry_get_text( GTK_ENTRY(widget) ),"%d", &NewValue); break;
		case VAR_SPY_MODE_DEC_UNSIGNED: 
				sscanf (gtk_entry_get_text( GTK_ENTRY(widget) ),"%u", &NewValue); break;
		case VAR_SPY_MODE_HEX: 
				sscanf (gtk_entry_get_text( GTK_ENTRY(widget) ),"%x", &NewValue); break;
		case VAR_SPY_MODE_BIN: 
				NewValue = ConvBinToInt( gtk_entry_get_text( GTK_ENTRY(widget) ) ); break;
	}

	if ( InfosGUI->TargetMonitor.RemoteConnected )
	{
		ShowMessageBox("Error", "Actually, not possible on a connected remote target...","Ok");
	}
	else
	{
		WriteVar( CurrentModifyVarType, CurrentModifyVarOffset, NewValue );
	}
	// show the converted value entered we have understand!
	FormatVariableValue( BufferValue, InfosGUI->FreeVarSpyDisplayFormat[NumVarSpy], NewValue );
	gtk_entry_set_text( GTK_ENTRY(widget), BufferValue );
	LatestEditedVarValue[NumVarSpy] = NewValue;

	return TRUE;
}

void DisplayFreeVarSpy()
{
	int NumVarSpy;
	char BufferValue[50];
	char * Days[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
	int Time = ReadVar( VAR_WORD_SYSTEM, 0 );
	int Date = ReadVar( VAR_WORD_SYSTEM, 1 );
	sprintf( BufferValue, "%s %d/%d/%d %d:%02d:%02d", Days[ ReadVar( VAR_WORD_SYSTEM,2 ) ],
					2000+Date/10000, Date/100%100, Date%100, Time/10000, Time/100%100, Time%100 );
	gtk_entry_set_text(GTK_ENTRY(EntryDateTime),BufferValue);
	for (NumVarSpy=0; NumVarSpy<NBR_FREE_VAR_SPY; NumVarSpy++)
	{
		FormatVariableValue( BufferValue, InfosGUI->FreeVarSpyDisplayFormat[NumVarSpy], 
								ReadVar(InfosGUI->FreeVarSpy[NumVarSpy].VarType,InfosGUI->FreeVarSpy[NumVarSpy].VarNum) );
		gtk_entry_set_text( GTK_ENTRY(EntryVarSpy[NBR_FREE_VAR_SPY+NumVarSpy]), BufferValue );
	}
}
/* if OnlyThisOne = -1 => all */
void UpdateAllLabelsFreeVars( int OnlyThisOne, char * VarName )
{
	int NumVarSpy;
	char BufferValue[50];
	for (NumVarSpy=0; NumVarSpy<NBR_FREE_VAR_SPY; NumVarSpy++)
	{
		if ( OnlyThisOne==-1 || NumVarSpy==OnlyThisOne )
		{
			char * OtherVarName = NULL;
			char TestVarIsABool = FALSE;
			StrIdVar * pIdVar = &InfosGUI->FreeVarSpy[NumVarSpy];
			if ( OnlyThisOne==-1 )
				VarName = CreateVarName(pIdVar->VarType,pIdVar->VarNum,InfosGene->DisplaySymbols);
			// first column = variable name
			gtk_entry_set_text((GtkEntry *)EntryVarSpy[ NumVarSpy ],VarName);
			if ( VarName[ 0 ]=='%' )
				OtherVarName = ConvVarNameToSymbol( VarName );
			else
				OtherVarName = ConvSymbolToVarName( VarName );
			if ( OtherVarName==NULL )
				OtherVarName = "";
			gtk_tooltips_set_tip( TooltipsEntryVarSpy[ NumVarSpy ], EntryVarSpy[ NumVarSpy ], OtherVarName, NULL );
			// second column = current value
			gtk_entry_set_text((GtkEntry *)EntryVarSpy[NBR_FREE_VAR_SPY+NumVarSpy], "");
			// format display combo => set to "bin" if boolean variable
			TestVarIsABool = TEST_VAR_IS_A_BOOL( pIdVar->VarType, pIdVar->VarNum );
			gtk_combo_box_set_active( GTK_COMBO_BOX( DisplayFormatVarSpy[NumVarSpy] ), TestVarIsABool?VAR_SPY_MODE_BIN:InfosGUI->FreeVarSpyDisplayFormat[NumVarSpy] );
			gtk_widget_set_sensitive( DisplayFormatVarSpy[NumVarSpy], !TestVarIsABool );
			// latest edited value entry
			gtk_entry_set_text((GtkEntry *)EditVarSpyValue[NumVarSpy], FormatVariableValue(BufferValue, InfosGUI->FreeVarSpyDisplayFormat[NumVarSpy], 
				LatestEditedVarValue[NumVarSpy]));    
			gtk_widget_set_sensitive( EditVarSpyValue[ NumVarSpy ], TestVarIsReadWrite( pIdVar->VarType, pIdVar->VarNum ) );
		}
	}
}

gint FreeVarsWindowDeleteEvent( GtkWidget * widget, GdkEvent * event, gpointer data )
{
// Here, we must only toggle the menu check that will call itself the function below to close the window ...
//	gtk_widget_hide( SpyFreeVarsWindow );
	SetToggleMenuForFreeVarsWindow( FALSE/*OpenedWin*/ );
	// we do not want that the window be destroyed.
	return TRUE;
}

// called per toggle action menu, or at startup (if window saved open or not)...
void OpenSpyFreeVarsWindow( GtkAction * ActionOpen, gboolean OpenIt )
{
	if ( ActionOpen!=NULL )
		OpenIt = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(ActionOpen) );
	if ( OpenIt )
	{
		RestoreWindowPosiPrefs( "FreeVars", SpyFreeVarsWindow );
		gtk_widget_show( SpyFreeVarsWindow );
		gtk_window_present( GTK_WINDOW(SpyFreeVarsWindow) );
	}
	else
	{
		RememberWindowPosiPrefs( "FreeVars", SpyFreeVarsWindow, FALSE/*SaveWindowSize*/ );
		gtk_widget_hide( SpyFreeVarsWindow );
	}
}
void RememberFreeVarsWindowPrefs( void )
{
	char WindowIsOpened = GTK_WIDGET_VISIBLE( GTK_WINDOW(SpyFreeVarsWindow) );
	RememberWindowOpenPrefs( "FreeVars", WindowIsOpened );
	if ( WindowIsOpened )
		RememberWindowPosiPrefs( "FreeVars", SpyFreeVarsWindow, FALSE/*SaveWindowSize*/ );
}

void AddDisplayFormatItems( GtkComboBox * pComboBox )
{
	gtk_combo_box_append_text( pComboBox, "Dec +/-" );
	gtk_combo_box_append_text( pComboBox, "Dec +" );
	gtk_combo_box_append_text( pComboBox, "Hex" );
	gtk_combo_box_append_text( pComboBox, "Bin" );
	gtk_combo_box_set_active( GTK_COMBO_BOX( pComboBox ), 0 );
}

GtkWidget * CreateFreeVarsPage( )
{
	GtkWidget * hboxfreevars[ 1+NBR_FREE_VAR_SPY ], *vboxMain;
	long ColumnVar;
	int NumLine,NumVarSpy,NumEntry;
//	GList *DisplayFormatItems = NULL;

//	DisplayFormatItems = g_list_append(DisplayFormatItems,"Dec");
//	DisplayFormatItems = g_list_append(DisplayFormatItems,"Hex");
//	DisplayFormatItems = g_list_append(DisplayFormatItems,"Bin");
	
	vboxMain = gtk_vbox_new (FALSE, 0);
	for(NumLine=0; NumLine<1+NBR_FREE_VAR_SPY; NumLine++)
	{
		hboxfreevars[ NumLine ] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vboxMain), hboxfreevars[ NumLine ]);
//		gtk_widget_show (hboxfreevars[ NumLine ]);
		if ( NumLine==0 )
		{
			GtkWidget * ModifyLabelInfo;
			EntryDateTime = gtk_entry_new( );
			gtk_box_pack_start (GTK_BOX( hboxfreevars[ NumLine ] ), EntryDateTime, TRUE, TRUE, 0);
			gtk_editable_set_editable( GTK_EDITABLE(EntryDateTime), FALSE);
			gtk_widget_set_usize(EntryDateTime,110*2+80,0);
//			gtk_widget_show( EntryDateTime );
			ModifyLabelInfo = gtk_label_new("Modify Value :");
			gtk_label_set_justify ( GTK_LABEL(ModifyLabelInfo), GTK_JUSTIFY_CENTER );
			gtk_box_pack_start (GTK_BOX( hboxfreevars[ NumLine ] ), ModifyLabelInfo, TRUE, TRUE, 0);
//			gtk_widget_show( ModifyLabelInfo );
		}
		else
		{
			NumVarSpy = NumLine-1;
			//First column: variable name, Second column: current value
			for(ColumnVar=0; ColumnVar<2; ColumnVar++)
			{
				NumEntry = NumVarSpy+ColumnVar*NBR_FREE_VAR_SPY;
				EntryVarSpy[ NumEntry ] = gtk_entry_new();
				gtk_widget_set_usize((GtkWidget *)EntryVarSpy[ NumEntry ],110,0);
				gtk_entry_set_alignment ((GtkEntry *)EntryVarSpy[ NumEntry ], (ColumnVar==1)?1:0);
				gtk_box_pack_start (GTK_BOX( hboxfreevars[ NumLine ] ), EntryVarSpy[ NumEntry ], TRUE, TRUE, 0);
//				gtk_widget_show(EntryVarSpy[NumEntry]);
				if ( ColumnVar==0 )
				{
					TooltipsEntryVarSpy[ NumVarSpy ] = gtk_tooltips_new();
					gtk_signal_connect(GTK_OBJECT (EntryVarSpy[ NumEntry ]), "activate",
	                                        (GtkSignalFunc) EntryVarSpy_activate_event, (void *)NumVarSpy);
				}
				else
				{
					gtk_editable_set_editable( GTK_EDITABLE(EntryVarSpy[ NumEntry ]), FALSE );
				}
			}

//			DisplayFormatVarSpy[NumVarSpy] = gtk_combo_new();
//			gtk_combo_set_value_in_list(GTK_COMBO(DisplayFormatVarSpy[NumVarSpy]), TRUE /*val*/, FALSE /*ok_if_empty*/);
//			gtk_combo_set_popdown_strings(GTK_COMBO(DisplayFormatVarSpy[NumVarSpy]), DisplayFormatItems);
//			gtk_widget_set_usize((GtkWidget *)DisplayFormatVarSpy[NumVarSpy],65,0);
//			gtk_box_pack_start (GTK_BOX(hboxfreevars[ NumLine ]), DisplayFormatVarSpy[NumVarSpy], FALSE, FALSE, 0);
//			gtk_widget_show(DisplayFormatVarSpy[NumVarSpy]);
			DisplayFormatVarSpy[NumVarSpy] = gtk_combo_box_new_text();
			AddDisplayFormatItems( GTK_COMBO_BOX( DisplayFormatVarSpy[NumVarSpy] ) );
			gtk_widget_set_usize((GtkWidget *)DisplayFormatVarSpy[NumVarSpy],80,0);
			gtk_box_pack_start (GTK_BOX(hboxfreevars[ NumLine ]), DisplayFormatVarSpy[NumVarSpy], FALSE, FALSE, 0);
//			gtk_widget_show(DisplayFormatVarSpy[NumVarSpy]);
	
// Modified by helitp@arrakis.es 19/7/2011 to replace popup window to modify value by new edit widget column on right.
//			ModifyVarSpy[NumVarSpy] = gtk_button_new();
//			gtk_button_set_image( GTK_BUTTON ( ModifyVarSpy[NumVarSpy] ),
//	                        gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_SMALL_TOOLBAR) );
//			gtk_box_pack_start (GTK_BOX(hboxfreevars[ NumLine ]), ModifyVarSpy[NumVarSpy], FALSE, FALSE, 0);
//			gtk_widget_show(ModifyVarSpy[NumVarSpy]);
//			gtk_signal_connect( GTK_OBJECT(ModifyVarSpy[ NumVarSpy ]), "clicked",
//	                                        (GtkSignalFunc)OpenModifyVarWindow_clicked_event, (void *)NumVarSpy );

			gtk_signal_connect(GTK_OBJECT( DisplayFormatVarSpy[NumVarSpy] ), "changed", 
									(GtkSignalFunc)ComboBox_changed_event, (void *)NumVarSpy );
			gtk_signal_connect(GTK_OBJECT( DisplayFormatVarSpy[NumVarSpy] ), "popup", 
									(GtkSignalFunc)ComboBox_changed_event, (void *)NumVarSpy );

			NumEntry = NumVarSpy;
			EditVarSpyValue[ NumEntry ] = gtk_entry_new();
			gtk_widget_set_usize(EditVarSpyValue[ NumEntry ],110,0);
			gtk_entry_set_text( GTK_ENTRY(EditVarSpyValue[ NumEntry ]),"0" );
			LatestEditedVarValue[NumVarSpy] = 0;
			gtk_entry_set_alignment ((GtkEntry *)EditVarSpyValue[ NumEntry ], 1);
			gtk_box_pack_start (GTK_BOX( hboxfreevars[ NumLine ] ), EditVarSpyValue[ NumEntry ], TRUE, TRUE, 0);
//			gtk_widget_show(EditVarSpyValue[NumEntry]);

			gtk_editable_set_editable( GTK_EDITABLE(EditVarSpyValue[ NumEntry ]), TRUE );
			gtk_signal_connect(GTK_OBJECT (EditVarSpyValue[ NumEntry ]), "activate", 
	                                        (GtkSignalFunc)EditVarSpyValue_changed_event, (void *)NumVarSpy );
        }
	}
	
	UpdateAllLabelsFreeVars( -1/*OnlyThisOne*/, NULL );

	return vboxMain;
}
void SignalTargetInfosPageSelected( GtkNotebook * notebook, GtkNotebookPage * page, guint page_num, gpointer user_data )
{
	if ( page_num==1 )
		DisplayProjectProperties( );
	if ( page_num==2 )
	{
		int NumLine;
		for(NumLine=0; NumLine<NBR_TARGET_INFOS; NumLine++)
		{
			gtk_entry_set_text( GTK_ENTRY(TargetInfoEntry[ NumLine ]), !InfosGUI->TargetMonitor.RemoteConnected?"Not connected":"---" );
		}
		InfosGUI->TargetMonitor.AskTargetToGetTargetInfos = 1;
	}
}
void DisplayTargetInfosVersion( void )
{
	gtk_entry_set_text( GTK_ENTRY(TargetInfoEntry[ 0 ]), InfosGUI->TargetMonitor.InfoSoftVersion );
	gtk_entry_set_text( GTK_ENTRY(TargetInfoEntry[ 1 ]), InfosGUI->TargetMonitor.InfoKernelVersion );
	gtk_entry_set_text( GTK_ENTRY(TargetInfoEntry[ 2 ]), InfosGUI->TargetMonitor.InfoLinuxDistribVersion );
}
GtkWidget * CreateTargetInfosPage( )
{
	GtkWidget * hbox[ NBR_TARGET_INFOS ], *vboxMain;
	int NumLine;
	GtkWidget * pLabel;
	char * Text[ NBR_TARGET_INFOS ] = {"ClassicLadder Soft.Version","Kernel Version","Linux Distribution"};
	vboxMain = gtk_vbox_new (FALSE, 0);
	for(NumLine=0; NumLine<NBR_TARGET_INFOS; NumLine++)
	{
		hbox[ NumLine ] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vboxMain), hbox[ NumLine ]);

		pLabel = gtk_label_new(Text[NumLine]);
//		gtk_label_set_justify ( GTK_LABEL(pLabel), GTK_JUSTIFY_CENTER );
		gtk_box_pack_start (GTK_BOX( hbox[ NumLine ] ), pLabel, TRUE, TRUE, 0);

		TargetInfoEntry[ NumLine ] = gtk_entry_new( );
		gtk_box_pack_start (GTK_BOX( hbox[ NumLine ] ), TargetInfoEntry[ NumLine ], TRUE, TRUE, 0);
		gtk_editable_set_editable( GTK_EDITABLE(TargetInfoEntry[ NumLine ]), FALSE);
	}
	return vboxMain;
}
void DisplayProjectProperties( void )
{
	gtk_entry_set_text( GTK_ENTRY(ProjectInfoEntry[ 0 ]), InfosGene->ProjectProperties.ProjectName );
	gtk_entry_set_text( GTK_ENTRY(ProjectInfoEntry[ 1 ]), InfosGene->ProjectProperties.ParamAuthor );
	gtk_entry_set_text( GTK_ENTRY(ProjectInfoEntry[ 2 ]), InfosGene->ProjectProperties.ParamVersion );
	gtk_entry_set_text( GTK_ENTRY(ProjectInfoEntry[ 3 ]), InfosGene->ProjectProperties.ParamCreaDate );
	gtk_entry_set_text( GTK_ENTRY(ProjectInfoEntry[ 4 ]), InfosGene->ProjectProperties.ParamModifDate );
}
void ButtonApplyProjectProperties( )
{
	strcpy( InfosGene->ProjectProperties.ProjectName, gtk_entry_get_text( GTK_ENTRY( ProjectInfoEntry[ 0 ] ) ) );
	strcpy( InfosGene->ProjectProperties.ParamAuthor, gtk_entry_get_text( GTK_ENTRY( ProjectInfoEntry[ 1 ] ) ) );
	strcpy( InfosGene->ProjectProperties.ParamVersion, gtk_entry_get_text( GTK_ENTRY( ProjectInfoEntry[ 2 ] ) ) );
}
GtkWidget * CreateProjectPropertiesPage( )
{
	GtkWidget * hbox[ NBR_PROJECT_INFOS+1 ], *vboxMain;
	int NumLine;
	GtkWidget * pLabel;
	GtkWidget * pApplyButton;
	char * Text[ NBR_PROJECT_INFOS ] = {"Project Name","Author","Param.Version","Creation Date","Modify Date"};
	vboxMain = gtk_vbox_new (FALSE, 0);
	for(NumLine=0; NumLine<NBR_PROJECT_INFOS+1; NumLine++)
	{
		hbox[ NumLine ] = gtk_hbox_new (FALSE, 0);
		gtk_container_add (GTK_CONTAINER (vboxMain), hbox[ NumLine ]);

		if ( NumLine<NBR_PROJECT_INFOS )
		{
			pLabel = gtk_label_new(Text[NumLine]);
//			gtk_label_set_justify ( GTK_LABEL(pLabel), GTK_JUSTIFY_CENTER );
			gtk_box_pack_start (GTK_BOX( hbox[ NumLine ] ), pLabel, TRUE, TRUE, 0);

			ProjectInfoEntry[ NumLine ] = gtk_entry_new( );
			gtk_box_pack_start (GTK_BOX( hbox[ NumLine ] ), ProjectInfoEntry[ NumLine ], TRUE, TRUE, 0);
			if ( NumLine>=3 )
				gtk_editable_set_editable( GTK_EDITABLE(ProjectInfoEntry[ NumLine ]), FALSE);
		}
		else
		{
			pApplyButton = gtk_button_new_with_label("Apply");
			gtk_box_pack_start(GTK_BOX(hbox[ NumLine ]),pApplyButton,TRUE,FALSE,0);
			gtk_signal_connect(GTK_OBJECT(pApplyButton), "clicked", 
				(GtkSignalFunc) ButtonApplyProjectProperties, 0);
		}
	}
	return vboxMain;
}
void FreeVarsWindowInitGtk( )
{
	GtkWidget *nbook;

	SpyFreeVarsWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title ((GtkWindow *)SpyFreeVarsWindow, "Spy free vars");
	
	nbook = gtk_notebook_new( );
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateFreeVarsPage( ),
				 gtk_label_new ("Vars & Time") );
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateProjectPropertiesPage( ),
				 gtk_label_new ("Project properties") );
	gtk_notebook_append_page( GTK_NOTEBOOK(nbook), CreateTargetInfosPage( ),
				 gtk_label_new ("Target infos") );
	gtk_container_add( GTK_CONTAINER (SpyFreeVarsWindow), nbook );
	gtk_signal_connect( GTK_OBJECT(nbook), "switch-page",
                                        (GtkSignalFunc) SignalTargetInfosPageSelected, (void *)NULL );
	gtk_widget_show_all( SpyFreeVarsWindow );

	gtk_signal_connect( GTK_OBJECT(SpyFreeVarsWindow), "delete_event",
		(GtkSignalFunc)FreeVarsWindowDeleteEvent, 0 );
}


void VarsWindowInitGtk()
{
	FreeVarsWindowInitGtk( );
	BoolVarsWindowInitGtk( );
//	ModifyVarWindowInitGtk( );
}

